package com.codi.bus.core.service.impl;

import com.codi.base.log.annotation.Loggable;
import com.codi.base.util.*;
import com.codi.bus.constant.FundBusinCodeUtil;
import com.codi.bus.constant.FundConst;
import com.codi.bus.constant.GlobalConstant;
import com.codi.bus.constant.RuleConstant;
import com.codi.bus.core.dao.FundCombinationDao;
import com.codi.bus.core.dao.LookupDao;
import com.codi.bus.core.dao.UserDao;
import com.codi.bus.core.domain.FundCombination;
import com.codi.bus.core.domain.Lookup;
import com.codi.bus.core.domain.User;
import com.codi.bus.core.resultModel.*;
import com.codi.bus.core.service.ApplyRecordService;
import com.codi.bus.core.service.FundDetailService;
import com.codi.bus.core.service.model.*;
import com.codi.bus.core.service.util.CalculateAssetsUtils;
import com.codi.bus.core.service.util.HundsunUtils;
import com.codi.bus.core.service.util.ModelPopulateUtils;
import com.codi.bus.exception.BaseException;
import com.codi.bus.exception.SystemDBException;
import com.codi.fundData.domain.FundDetail;
import com.codi.message.constant.ErrorConstant;
import com.codi.message.util.MessageUtil;
import com.codi.trade.dto.HsDividendQryDto;
import com.codi.trade.service.DividendsQueryService;
import com.codi.trade.service.TradeApplyQueryService;
import com.codi.trade.service.TradeConfirmQueryService;
import com.google.common.base.Function;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.Predicate;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author lvgo
 * @version 4.5.0
 * @Description: // 交易记录
 * @date 2018/4/9 11:05
 */
@Service
@Slf4j
public class ApplyRecordServiceImpl implements ApplyRecordService {


    @Resource(name = "userDao")
    private UserDao userDao;

    @Autowired
    private DividendsQueryService dividendsQueryService;

    @Resource(name = "tradeApplyQueryService")
    private TradeApplyQueryService tradeApplyQueryService;

    @Resource(name = "lookupDao")
    private LookupDao lookupDao;

    @Resource(name = "tradeConfirmQueryService")
    private TradeConfirmQueryService tradeConfirmQueryService;

    @Resource(name = "fundDetailService")
    private FundDetailService fundDetailService;

    @Autowired
    private FundCombinationDao fundCombinationDao;

    /**
     * 资产--组合交易记录
     *
     * @param tradeAccount 组合交易代码 非必
     * @param queryType     业务类型, all 全部 onWay 进行中
     * @param userId        用户id
     * @param business
     * @return
     */
    @Override
    @Loggable
    public PTradingRecordListResult queryPortfolioRecord(String tradeAccount, String queryType, Long userId, Integer beginNum, Integer requestNum, String business, String portfolioAllotNo) {
        log.info("queryApplys - userId=" + userId);
        PTradingRecordListResult ptResult = new PTradingRecordListResult();
        PortfolioApplyListResult result = new PortfolioApplyListResult();
        try {
            // 获取用户
            User user = userDao.getEntity(userId);
            // 判断是否已开户
            if (user == null || StringUtil.isEmpty(user.getExternalClientId())) {
                ptResult.setSuccess(false);
                ptResult.setErrorType(GlobalConstant.ERROR_TYPE_APPLICATION);
                ptResult.setErrorCode(ErrorConstant.ERROR_NO_ACCOUNT);
                return ptResult;
            }
            // 查出这个用户下所有的交易记录，包括已确认和未确认的，传ClientId
            Map<String, Object> map = new HashMap<>();
            if (StringUtils.isNotBlank(portfolioAllotNo)) {
                map = tradeApplyQueryService.queryForPortfolio(GlobalConstant.MAX_REQUEST_NUM, 1, 1, "1", "", user.getExternalClientId(), "", "", "", "", "", "", "", "", "", "", "", "", portfolioAllotNo);
            } else {
                map = tradeApplyQueryService.query(GlobalConstant.MAX_REQUEST_NUM, 1, 1, "1", "", user.getExternalClientId(), "", "", "", "", "", "", "", "", "", "", "", "");
            }
            // 查询结果
            List<Map<String, Object>> list = new ArrayList<>();
            HundsunUtils.ConvertToList(map, list, ptResult);
            if (!ptResult.getSuccess()) {
                ptResult.setSuccess(false);
                ptResult.setErrorType(GlobalConstant.ERROR_TYPE_SYSTEM);
                ptResult.setErrorCode(ErrorConstant.ERROR_HUNDSUNAPI_WRONG);
                ptResult.setErrorMessage(result.getErrorMessage());
                return ptResult;
            }

            // 交易业务名称
            List<Lookup> tradeLookups = lookupDao.getLookupByType(RuleConstant.RULE_LOOKUP_TYPE_BUSINAME);
            // 银行名称
            List<Lookup> bankLookups = lookupDao.getLookupByType(RuleConstant.RULE_LOOKUP_TYPE_HSBANK);
            // populate
            List<PortfolioApplyModel> applys = ModelPopulateUtils.populatePortfolioApply(list, result, tradeLookups, bankLookups, user.getIsOrg());

            List<ApplyModel> applys2 = ModelPopulateUtils.populateApply2(list, result, tradeLookups, bankLookups, user.getIsOrg());
            map = tradeConfirmQueryService.query(GlobalConstant.MAX_REQUEST_NUM, 1, 1, "1", "", user.getExternalClientId(), "", "", "", "", "", "", "", "", "", "", "", "", "", "");
            // 查询结果
            list = new ArrayList<>();
            HundsunUtils.ConvertToList(map, list, ptResult);
            if (!ptResult.getSuccess()) {
                return ptResult;
            }
            // populate
            List<ConfirmModel> confirms = ModelPopulateUtils.populateConfirm(list);
            // 从聚源获取基金信息
            List<String> fundCodeList = new ArrayList<>();
            for (ApplyModel shareModel : applys) {
                if (!fundCodeList.contains(shareModel.getFundCode())) {
                    fundCodeList.add(shareModel.getFundCode());
                }
                shareModel.setIsOrg(user.getIsOrg());
            }
            /*
             * 从聚源获取基金信息
             */
            List<FundNetValueResult> fundNetValueList;
            try {
                // 获取聚源数据
                fundNetValueList = fundDetailService.getFundNetValueByBatch(fundCodeList, new Date());
            } catch (Exception ex) {
                ExceptionUtil.logError(log, "queryApplys - fundDetailService - Exception:", ex);
                ptResult.setSuccess(false);
                ptResult.setErrorCode(ErrorConstant.ERROR_GILDATA_WRONG);
                ptResult.setErrorType(GlobalConstant.ERROR_TYPE_SYSTEM);
                return ptResult;
            }
            // 如果没有找到聚源数据，则默认为空数组
            if (fundNetValueList == null) {
                fundNetValueList = new ArrayList<>();
            }
            Map<String, PortfolioApplyModel> modelMap = new HashMap<>();
            /*
             * 将相同组合中的记录合并     并过滤非组合的记录
             */

            for (PortfolioApplyModel portfolioApplyModel : applys) {
                //过滤非组合 记录
                if ("".equals(portfolioApplyModel.getPortfolioCode())) {
                    continue;
                }

//                //过滤组合单号
//                if (StringUtils.isNotBlank(portfolioAllotNo)){
//                    if (!portfolioAllotNo.equals(portfolioApplyModel.getPortfolioAllotNo())){
//                        continue;
//                    }
//                }
                //如果map 中已经有这个集合  就把金额和份额相加 并向二级列表中加入一条记录
                else if (modelMap.containsKey(portfolioApplyModel.getPortfolioAllotNo())) {
                    modelMap.get(portfolioApplyModel.getPortfolioAllotNo()).setBalance(MoneyUtils.add(modelMap.get(portfolioApplyModel.getPortfolioAllotNo()).getBalance(), portfolioApplyModel.getBalance()));
                    modelMap.get(portfolioApplyModel.getPortfolioAllotNo()).setShares(MoneyUtils.add(modelMap.get(portfolioApplyModel.getPortfolioAllotNo()).getShares(), portfolioApplyModel.getShares()));
                    //如果是 43或者06  说明是 组合调仓   要把业务辅助编码设置为 43或者06  用于后面的判断  其他地方并不会用到这个业务辅助编码
                    if (GlobalConstant.BUSIN_ASS_CODE_CURRENCY_SEEL_THEN_BUY.equals(portfolioApplyModel.getBusinAssCode()) || GlobalConstant.BUSIN_ASS_CODE_SELL_THEN_BUY_CURRENCY.equals(portfolioApplyModel.getBusinAssCode())) {
                        modelMap.get(portfolioApplyModel.getPortfolioAllotNo()).setBusinAssCode(portfolioApplyModel.getBusinAssCode());
                    }
                } else {
                    modelMap.put(portfolioApplyModel.getPortfolioAllotNo(), portfolioApplyModel);
                }
            }

            List<PortfolioApplyModel> portfolioApplys = new ArrayList<>();
            for (String key : modelMap.keySet()) {
                portfolioApplys.add(modelMap.get(key));
            }
            /*
             * 设置是否机构  并创建二级记录  组合中具体基金的交易记录
             */
            List<FundCombination> fundCombinations = fundCombinationDao.queryFundCombinations();

            for (PortfolioApplyModel portfolioApplyModel : portfolioApplys) {
                if (Strings.isNullOrEmpty(portfolioApplyModel.getProtocolName())) {
                    for (ApplyModel applyModel : applys) {
                        if ("022".equals(applyModel.getFundBusinCode()) && portfolioApplyModel.getTradeAcco().equals(applyModel.getTradeAcco())) {
                            portfolioApplyModel.setProtocolName(applyModel.getProtocolName());
                        }
                    }
                }
                if (GlobalConstant.BUSIN_ASS_CODE_CURRENCY_SEEL_THEN_BUY.equals(portfolioApplyModel.getBusinAssCode()) || GlobalConstant.BUSIN_ASS_CODE_SELL_THEN_BUY_CURRENCY.equals(portfolioApplyModel.getBusinAssCode())) {
                    portfolioApplyModel.setFundBusinName(GlobalConstant.PORTFOLIO_TRANSFER);
                    portfolioApplyModel.setIsTransfer(true);
                } else {
                    portfolioApplyModel.setIsTransfer(false);
                }
                List<ApplyModel> applyModels = new ArrayList<>();
                portfolioApplyModel.setFundApplys(applyModels);
                portfolioApplyModel.setIsOrg(user.getIsOrg());

                //万一没名字  那就加名字
                if (StringUtils.isBlank(portfolioApplyModel.getProtocolName())) {
                    for (FundCombination fundCombination : fundCombinations) {
                        if (fundCombination.getCombinationCode().equals(portfolioApplyModel.getPortfolioCode())) {
                            portfolioApplyModel.setProtocolName(fundCombination.getCombinationName());
                        }
                    }
                }
            }
            /*
             * 添加组合信息  并加入组合中基金的具体信息
             */
            // 判断是否有在途的交易
            boolean inTransit = false;
            for (PortfolioApplyModel portfolioApplyModel : portfolioApplys) {
                // 未确认并且不能是无效扣款状态
                if (portfolioApplyModel.getTAConfirmFlag().equals(GlobalConstant.TACONFIRM_FLAG_UNCONFIRM)
                    && !portfolioApplyModel.getDeductStatus().equals(GlobalConstant.DEDUCT_STATUS_INVALID)) {
                    inTransit = true;
                }
                for (ApplyModel apply : applys2) {
                    if (portfolioApplyModel.getPortfolioAllotNo().equals(apply.getPortfolioAllotNo())) {
                        setApply(confirms, apply, fundNetValueList, portfolioApplyModel);
                    }
                    switch (apply.getFundBusinCode()) {
                        //申购
                        case GlobalConstant.FUND_BUSIN_CODE_APPLY_BUY:
                            apply.setExpenseTtile(GlobalConstant.BUY_TRADE_CONFIRM_EXPENSE_TITLE);
                            break;
                        //赎回
                        case GlobalConstant.FUND_BUSIN_CODE_APPLY_SELL:
                            apply.setExpenseTtile(GlobalConstant.SELL_TRADE_CONFIRM_EXPENSE_TITLE);
                            break;
                        default:
                            break;
                    }
                }

            }

            //塞完之后再塞一遍  组合调仓的申购记录需要这样操作
            for (PortfolioApplyModel portfolioApplyModel : portfolioApplys) {
                for (ApplyModel apply : applys2) {
                    if (portfolioApplyModel.getFundApplys() != null) {
                        List<ApplyModel> applyModels = new ArrayList<>();
                        applyModels.addAll(portfolioApplyModel.getFundApplys());


                        for (ApplyModel applyModel : applyModels) {
                            if (applyModel.getAllotNo().equals(apply.getOriginalAppno())) {
                                setApply(confirms, apply, fundNetValueList, portfolioApplyModel);
                            }
                        }
                    }
                }
                /*
                 * 新增组合调仓的状态判断 和 普通的申购赎回区分
                 * zx 2018年3月21日10:14:30
                 */
                boolean confirm = false;
                boolean success = false;
                boolean fail = false;
                if (GlobalConstant.PORTFOLIO_TRANSFER.equals(portfolioApplyModel.getFundBusinName())) {
                    for (ApplyModel applyModel : portfolioApplyModel.getFundApplys()) {
                        if (applyModel.getTAConfirmFlag().equals(GlobalConstant.TACONFIRM_FLAG_UNCONFIRM)) {
                            confirm = true;
                        }
                        if (applyModel.getTAConfirmFlag().equals(GlobalConstant.TACONFIRM_FLAG_CONFIRMED)) {
                            success = true;
                        }
                        if (applyModel.getTAConfirmFlag().equals(GlobalConstant.TACONFIRM_FLAG_FAIL)) {
                            fail = true;
                        }
                    }
                    if (fail) {
                        portfolioApplyModel.setStatusString("确认失败");
                    } else if (confirm) {
                        portfolioApplyModel.setStatusString("申请成功");
                    } else if (success) {
                        portfolioApplyModel.setStatusString("确认成功");
                    } else {
                        portfolioApplyModel.setStatusString("确认失败");
                    }
                } else {
                    //zx 2018年3月28日11:28:53  这块代码针对 部分成功部分失败
                    for (ApplyModel applyModel : portfolioApplyModel.getFundApplys()) {
                        if (ModelPopulateUtils.getStatusString(applyModel).contains("成功")) {
                            portfolioApplyModel.setFundCode(applyModel.getFundCode());
                            portfolioApplyModel.setAllotNo(applyModel.getAllotNo());
                            portfolioApplyModel.setOrderDate(applyModel.getOrderDateReal());
                            portfolioApplyModel.setOrderTime(applyModel.getOrderTimeReal());
                            portfolioApplyModel.setBankCode(applyModel.getBankCode());
                            portfolioApplyModel.setBankHSCode(applyModel.getBankHSCode());
                            portfolioApplyModel.setBankName(applyModel.getBankName());
                            portfolioApplyModel.setDeductStatus(applyModel.getDeductStatus());
                            portfolioApplyModel.setCapitalMode(applyModel.getCapitalMode());
                            portfolioApplyModel.setTAConfirmFlag(applyModel.getTAConfirmFlag());
                            portfolioApplyModel.setFundBusinCode(applyModel.getFundBusinCode());
                            portfolioApplyModel.setFundBusinName(applyModel.getFundBusinNameReal());
                            portfolioApplyModel.setSendFlag(applyModel.getSendFlag());
                            portfolioApplyModel.setApplyDate(applyModel.getApplyDateReal());

                            break;
                        }
                    }
                    portfolioApplyModel.setStatusString(ModelPopulateUtils.getStatusString(portfolioApplyModel));
                }
            }
            // 4.5.0版本 交易记录整合查询接口
            // business 业务类型
            business = businessCode(business);


            // 正在进行中的交易
            List<PortfolioApplyModel> intradingApplys;
            // 指定组合的交易记录
            List<PortfolioApplyModel> portfolioCodeApplys;
            // 根据业务参数 查询交易记录
            List<PortfolioApplyModel> filtratePortfolioApplys;

            // 1.进行中的交易记录
            if (StringUtils.isNotBlank(queryType) && GlobalConstant.APPLY_RECORD_ONWAY.equals(queryType)) {
                intradingApplys = getIntradingApplys(portfolioApplys);
                portfolioApplys.clear();
                portfolioApplys.addAll(intradingApplys);
            }

            // 2.指定组合交易记录
            if (StringUtils.isNotBlank(tradeAccount)) {
                portfolioCodeApplys = getPortfolioCodeApplys(portfolioApplys, tradeAccount);
                portfolioApplys.clear();
                portfolioApplys.addAll(portfolioCodeApplys);
            }

            // 3.指定业务交易记录
            if (StringUtils.isNotBlank(business) && !GlobalConstant.FUND_BUSIN_CODE_APPLY_BOUNS.equals(business)) {
                filtratePortfolioApplys = busniessData(portfolioApplys, business);
                portfolioApplys.clear();
                portfolioApplys.addAll(filtratePortfolioApplys);
            }


            // 分红交易记录
            List<DividendModel> dividendModels = new ArrayList<>();
            boolean isAll = GlobalConstant.APPLY_RECORD_ALL.equals(queryType) && StringUtils.isBlank(business);
            boolean isBouns = GlobalConstant.APPLY_RECORD_ALL.equals(queryType) && (StringUtils.isNotBlank(business) && GlobalConstant.FUND_BUSIN_CODE_APPLY_BOUNS.equals(business));
            if (isAll || isBouns) {
                if (StringUtils.isNotBlank(portfolioAllotNo)) {
                    dividendModels = getPortfolioDividendApply(user, portfolioAllotNo);
                } else {
                    dividendModels = getPortfolioDividendApply(user, null);
                }
            }

            // 组装组合交易记录模型数据
            List<PTradingRecord> pTradingRecords = new ArrayList<>();
            List<PTradingRecord> pTradingRecordReal = new ArrayList<>();
            // 添加组合交易记录
            if (!GlobalConstant.FUND_BUSIN_CODE_APPLY_BOUNS.equals(business)) {
                for (PortfolioApplyModel portfolioApply : portfolioApplys) {
                    pTradingRecords.add(
                        PTradingRecord.builder()
                            .PortfolioApplyModel(portfolioApply)
                            .sortDate(portfolioApply.getAllotNo())
                            .state(0).build()
                    );
                }
            }
            if (StringUtils.isNotBlank(tradeAccount)) {
                dividendModels = dividendModels.stream()
                    .filter(dividendModel -> dividendModel.getTradeAccount().equals(tradeAccount))
                    .collect(Collectors.toList());
            }
            // 添加分红交易记录
            dividendModels.forEach(dividendModel -> pTradingRecords.add(
                PTradingRecord.builder()
                    .dividendModel(dividendModel)
                    .sortDate(dividendModel.getDividendDate() + "000000")
                    .state(1).build()
            ));


            // 处理数据进行排序
            filtrate(ptResult, pTradingRecords, pTradingRecordReal, beginNum, requestNum);

            ptResult.setSuccess(true);
            ptResult.setPTradingRecords(pTradingRecordReal);
            return ptResult;
        } catch (BaseException baseException) {
            throw baseException;
        } catch (Exception exception) {
            ExceptionUtil.logError(log, "queryApplys - Exception:", exception);
            throw new SystemDBException("queryApplys Failure!", exception);
        }
    }

    /**
     * 资产--基金的交易记录
     *
     * @param normalCode 基金代码 fundcode 非必
     * @param queryType  业务类型, all 全部 onWay 进行中
     * @param userId     用户id
     * @param beginNum
     * @param requestNum
     * @param business
     * @return
     */
    @Override
    public NTradingRecordListResult queryFundRecord(String normalCode, String queryType, Long userId, Integer beginNum, Integer requestNum, String business, String allotNo) {
        log.info("queryApplys - userId=" + userId);
        NTradingRecordListResult ntResult = new NTradingRecordListResult();
        ApplyListResult result = new ApplyListResult();
        try {
            // 获取用户
            User user = userDao.getEntity(userId);
            // 判断是否已开户
            if (user == null || StringUtil.isEmpty(user.getExternalClientId())) {
                ntResult.setSuccess(false);
                ntResult.setErrorType(GlobalConstant.ERROR_TYPE_APPLICATION);
                ntResult.setErrorCode(ErrorConstant.ERROR_NO_ACCOUNT);
                return ntResult;
            }


            //这里应该只需要查询非组合基金的交易记录  目前非组合基金的交易记录应该需要通过传tradeAccount来区分
            List<Map<String, Object>> list = new ArrayList<>();
            Map<String, Object> map = new HashMap<>();
            if (StringUtils.isNotBlank(allotNo)) {
                map = tradeApplyQueryService.query(GlobalConstant.MAX_REQUEST_NUM, 1, 1, "1", "",
                    user.getExternalClientId(), "", "", allotNo, "", "", "", "", "", "", "", "", "");
            } else {
                map = tradeApplyQueryService.query(GlobalConstant.MAX_REQUEST_NUM, 1, 1, "1", "",
                    user.getExternalClientId(), "", "", "", "", "", "", "", "", "", "", "", "");
            }
            // 查询结果
            HundsunUtils.ConvertToList(map, list, ntResult);
            if (!ntResult.getSuccess()) {
                ntResult.setSuccess(false);
                ntResult.setErrorType(GlobalConstant.ERROR_TYPE_SYSTEM);
                ntResult.setErrorCode(ErrorConstant.ERROR_HUNDSUNAPI_WRONG);
                ntResult.setErrorMessage(result.getErrorMessage());
                return ntResult;
            }
            // 交易业务名称
            List<Lookup> tradeLookups = lookupDao.getLookupByType(RuleConstant.RULE_LOOKUP_TYPE_BUSINAME);
            // 银行名称
            List<Lookup> bankLookups = lookupDao.getLookupByType(RuleConstant.RULE_LOOKUP_TYPE_HSBANK);
            // populate
            List<ApplyModel> fundApplys = ModelPopulateUtils.populateApply2(list, result, tradeLookups, bankLookups, user.getIsOrg());

            //过滤组合基金
            List<ApplyModel> applys = new ArrayList<>();
            for (ApplyModel applyModel : fundApplys) {
                //赎回转购的业务辅助标识
                if (GlobalConstant.BUSIN_ASS_CODE_CURRENCY_SEEL_THEN_BUY.equals(applyModel.getBusinAssCode())) {
                    if (!Strings.isNullOrEmpty(applyModel.getOriginalAppno())) {
                        for (ApplyModel apply : fundApplys) {
                            if (applyModel.getOriginalAppno().equals(apply.getAllotNo())) {
                                applyModel.setBusinAssName(apply.getFundCode());
                            }
                        }
                    }
                }
                if (GlobalConstant.BUSIN_ASS_CODE_SELL_THEN_BUY_CURRENCY.equals(applyModel.getBusinAssCode())) {
                    if (!Strings.isNullOrEmpty(applyModel.getTargetFundCode())) {
                        applyModel.setBusinAssName(applyModel.getTargetFundCode());
                    }
                }
                //过滤组合 记录
//                if (Strings.isNullOrEmpty(applyModel.getPortfolioCode()) ) {
//                    applys.add(applyModel);
//                }
                if (!applyModel.getTradeAcco().startsWith("ZH")) {
                    applys.add(applyModel);
                }
            }
            // 把T0基金过滤掉，因为T0基金有专门的页面来显示
            normalFilterT0(applys, true);

            // 从聚源获取基金信息
            List<String> fundCodeList = new ArrayList<String>();
            for (ApplyModel shareModel : applys) {
                if (!Strings.isNullOrEmpty(shareModel.getBusinAssName()) && !fundCodeList.contains(shareModel.getBusinAssName())) {
                    fundCodeList.add(shareModel.getBusinAssName());
                }
                if (!fundCodeList.contains(shareModel.getFundCode())) {
                    fundCodeList.add(shareModel.getFundCode());
                }
                shareModel.setIsOrg(user.getIsOrg());
            }

            List<FundNetValueResult> fundNetValueList = null;
            try {
                fundNetValueList = fundDetailService.getFundNetValueByBatch(fundCodeList, new Date());

            } catch (Exception ex) {
                ExceptionUtil.logError(log, "queryApplys - fundDetailService - Exception:", ex);
                ntResult.setSuccess(false);
                ntResult.setErrorType(GlobalConstant.ERROR_TYPE_SYSTEM);
                ntResult.setErrorCode(ErrorConstant.ERROR_GILDATA_WRONG);
                return ntResult;
            }

            // 如果没有找到聚源数据，则默认为空数组
            if (fundNetValueList == null) {
                fundNetValueList = new ArrayList<>();
            }

            for (ApplyModel model : applys) {
                // 设置基金信息
                for (FundNetValueResult fundNetValue : fundNetValueList) {
                    if (fundNetValue == null) {
                        continue;
                    }
                    if (fundNetValue.getFundCode().equals(model.getFundCode())) {
                        model.setFundName(fundNetValue.getChiNameAbbr());
                    }
                    if (fundNetValue.getFundCode().equals(model.getBusinAssName())) {
                        model.setBusinAssName("瑞富宝-" + fundNetValue.getChiNameAbbr());
                    }
                }

            }


            // business 业务类型
            business = businessCode(business);


            // 正在进行中的交易
            List<ApplyModel> intradingApplys;
            // 指定组合的交易记录
            List<ApplyModel> theCodeApplys;
            // 根据业务参数 查询交易记录
            List<ApplyModel> filtrateNormalApplys;

            // 1.进行中的交易记录
            if (StringUtils.isNotBlank(queryType) && GlobalConstant.APPLY_RECORD_ONWAY.equals(queryType)) {
                intradingApplys = getNormalIntradingApplys(applys);
                applys.clear();
                applys.addAll(intradingApplys);
            }

            // 2.指定基金交易记录
            if (StringUtils.isNotBlank(normalCode)) {
                theCodeApplys = getNormalCodeApplys(applys, normalCode);
                applys.clear();
                applys.addAll(theCodeApplys);
            }

            // 3.指定业务交易记录
            if (StringUtils.isNotBlank(business) && !GlobalConstant.FUND_BUSIN_CODE_APPLY_BOUNS.equals(business)) {
                filtrateNormalApplys = normalBusniessData(applys, business);
                applys.clear();
                applys.addAll(filtrateNormalApplys);
            }


            // 分红交易记录
            List<DividendModel> dividendModels = new ArrayList<>();
            boolean isAll = GlobalConstant.APPLY_RECORD_ALL.equals(queryType) && StringUtils.isBlank(business);
            boolean isBouns = GlobalConstant.APPLY_RECORD_ALL.equals(queryType) && (StringUtils.isNotBlank(business) && GlobalConstant.FUND_BUSIN_CODE_APPLY_BOUNS.equals(business));
            if (isAll || isBouns) {
                if (StringUtils.isNotBlank(allotNo)) {
                    dividendModels = getNormalDividendApplys(normalCode, user, allotNo);
                } else {
                    dividendModels = getNormalDividendApplys(normalCode, user, null);
                }
            }

            // 组装基金交易记录模型数据
            List<NTradingRecord> nTradingRecords = new ArrayList<>();
            List<NTradingRecord> nTradingRecordReal = new ArrayList<>();
            // 添加基金交易记录
            if (!GlobalConstant.FUND_BUSIN_CODE_APPLY_BOUNS.equals(business)) {
                applys.forEach(apply -> nTradingRecords.add(
                    NTradingRecord.builder()
                        .applyModel(apply)
                        .sortDate(apply.getAllotNo())
                        .state(0).build()
                ));
            }
            // 添加基金分红交易记录
            if (dividendModels != null) {
                dividendModels.forEach(dividendModel -> nTradingRecords.add(
                    NTradingRecord.builder()
                        .dividendModel(dividendModel)
                        .sortDate(dividendModel.getDividendDate() + "000000")
                        .state(1).build()
                ));
            }

            filtrateFunds(ntResult, nTradingRecords, nTradingRecordReal, beginNum, requestNum);
            ntResult.setNTradingRecords(nTradingRecordReal);
            return ntResult;
        } catch (BaseException baseException) {
            throw baseException;
        } catch (Exception exception) {
            ExceptionUtil.logError(log, "queryApplys - Exception:", exception);
            throw new SystemDBException("queryApplys Failure!", exception);
        }
    }

    /**
     * 资产--瑞富宝的交易记录
     *
     * @param fundCode   组合代码 非必
     * @param queryType  业务类型, all 全部 onWay 进行中
     * @param userId     用户id
     * @param beginNum
     * @param requestNum
     * @param business
     * @return
     */
    @Override
    public WTradingRecordListResult queryRuifubaoRecord(String fundCode, String queryType, Long userId, Integer beginNum, Integer requestNum, String business, String allotNo) {
        // 获取用户
        User user = userDao.getEntity(userId);
        WTradingRecordListResult wtResult = new WTradingRecordListResult();
        ApplyListResult result = new ApplyListResult();
        // 判断是否已开户
        if (user == null || StringUtil.isEmpty(user.getExternalClientId())) {
            wtResult.setSuccess(false);
            wtResult.setErrorType(GlobalConstant.ERROR_TYPE_APPLICATION);
            wtResult.setErrorCode(ErrorConstant.ERROR_NO_ACCOUNT);
            wtResult.setErrorMessage(MessageUtil.getErrorMsg(wtResult.getErrorCode()));
            return wtResult;
        }
        // 查出这个用户下所有的交易记录，包括已确认和未确认的，传ClientId
        Map<String, Object> map = new HashMap<>();
        if (StringUtils.isNotBlank(allotNo)) {
            map = tradeApplyQueryService.query(GlobalConstant.MAX_REQUEST_NUM, 1, 1, "1", "",
                user.getExternalClientId(), "", "", allotNo, "", "", "", "", "", "", "", "", "");
        } else {
            map = tradeApplyQueryService.query(GlobalConstant.MAX_REQUEST_NUM, 1, 1, "1", "",
                user.getExternalClientId(), "", "", "", "", "", "", "", "", "", "", "", "");
        }        // 检查查询结果是否OK
        List<Map<String, Object>> list = new ArrayList<>();
        HundsunUtils.ConvertToList(map, list, result);
        if (!result.getSuccess()) {
            wtResult.setSuccess(false);
            wtResult.setErrorType(GlobalConstant.ERROR_TYPE_SYSTEM);
            wtResult.setErrorCode(ErrorConstant.ERROR_HUNDSUNAPI_WRONG);
            wtResult.setErrorMessage(result.getErrorMessage());
            return wtResult;
        }
        // 银行名称
        List<Lookup> bankLookups = lookupDao.getLookupByType(RuleConstant.RULE_LOOKUP_TYPE_HSBANK);
        //如果传了T0基金代码
        Set<String> temp = new HashSet<String>();
        temp.add(fundCode);
        final Set<String> t0fundCodeSet = StringUtils.isNotBlank(fundCode) ? temp : CollectionsUtils.newSet(
            lookupDao.getLookupByType(RuleConstant.RULE_LOOKUP_TYPE_T0FUND), new Function<Lookup, String>() {
                @Override
                public String apply(Lookup input) {
                    return input.getRuleValue();
                }
            });

        List<Lookup> businLookups = lookupDao.getLookupByType(RuleConstant.RULE_LOOKUP_TYPE_BUSINAME);
        // populate
        List<ApplyModel> applys = ModelPopulateUtils.populateApply(list, result, businLookups, bankLookups);
        // 过滤非T0基金, 并修改T0基金fundBusinCode 为T0申购代码
        org.apache.commons.collections.CollectionUtils.filter(applys, new Predicate() {

            @Override
            public boolean evaluate(Object object) {
                ApplyModel am = (ApplyModel) object;
                am.setIsOrg(user.getIsOrg());
                String fundCode = am.getFundCode();
                if (!t0fundCodeSet.contains(fundCode)) {
                    return false;
                }
                String businCode = am.getFundBusinCode();
                if (FundBusinCodeUtil.isBuy(businCode) || FundBusinCodeUtil.isSell(businCode) || FundBusinCodeUtil.isFixBuy(businCode)) {
                    return true;
                }
                return false;
            }
        });

        List<FundNetValueResult> fundNetValueList = fundDetailService
            .getFundNetValueByBatch(Lists.newArrayList(t0fundCodeSet), new Date());
        // 如果没有找到聚源数据，则默认为空数组
        if (fundNetValueList == null) {
            fundNetValueList = new ArrayList<>();
        }

        for (ApplyModel model : applys) {
            if (GlobalConstant.BUSIN_ASS_CODE_CURRENCY_SEEL_THEN_BUY.equals(model.getBusinAssCode())) {
                model.setBusinAssName(GlobalConstant.BUSIN_ASS_NAME_CURRENCY_SEEL_THEN_BUY);

            }
            // 渲染模式为T0基金
            model.setFundType(ApplyModel.FundApplyType.T0);
            // 设置基金信息
            for (FundNetValueResult fundNetValue : fundNetValueList) {
                if (fundNetValue == null) {
                    continue;
                }
                if (fundNetValue.getFundCode().equals(model.getFundCode())) {
                    model.setFundName(fundNetValue.getChiNameAbbr());
                    break;
                }
            }
        }


        // business 业务类型
        business = businessCode(business);


        // 正在进行中的交易
        List<ApplyModel> intradingApplys;
        // 指定瑞富宝的交易记录
        List<ApplyModel> theCodeApplys;
        // 根据业务参数 查询交易记录
        List<ApplyModel> filtrateWalletApplys;

        // 1.进行中的交易记录
        if (StringUtils.isNotBlank(queryType) && GlobalConstant.APPLY_RECORD_ONWAY.equals(queryType)) {
            intradingApplys = getNormalIntradingApplys(applys);
            applys.clear();
            applys.addAll(intradingApplys);
        }

        // 2.指定瑞富宝交易记录
        if (StringUtils.isNotBlank(fundCode)) {
            theCodeApplys = getNormalCodeApplys(applys, fundCode);
            applys.clear();
            applys.addAll(theCodeApplys);
        }

        // 3.指定业务交易记录
        if (StringUtils.isNotBlank(business) && !GlobalConstant.FUND_BUSIN_CODE_APPLY_BOUNS.equals(business)) {
            filtrateWalletApplys = normalBusniessData(applys, business);
            applys.clear();
            applys.addAll(filtrateWalletApplys);
        }


        // 瑞富宝分红交易记录
        List<DividendModel> dividendModels = new ArrayList<>();
        boolean isAll = GlobalConstant.APPLY_RECORD_ALL.equals(queryType) && StringUtils.isBlank(business);
        boolean isBouns = GlobalConstant.APPLY_RECORD_ALL.equals(queryType) && (StringUtils.isNotBlank(business) && GlobalConstant.FUND_BUSIN_CODE_APPLY_BOUNS.equals(business));
        if (isAll || isBouns) {
            if (StringUtils.isNotBlank(allotNo)) {
                dividendModels = getWalletDividendApplys(user, allotNo);
            } else {
                dividendModels = getWalletDividendApplys(user, null);
            }
        }

        // 组装瑞富宝交易记录模型数据
        List<WTradingRecord> wTradingRecords = new ArrayList<>();
        List<WTradingRecord> wTradingRecordReal = new ArrayList<>();
        // 添加瑞富宝交易记录
        if (!GlobalConstant.FUND_BUSIN_CODE_APPLY_BOUNS.equals(business)) {
            applys.forEach(apply -> wTradingRecords.add(
                WTradingRecord.builder()
                    .applyModel(apply)
                    .sortDate(apply.getAllotNo())
                    .state(0).build()
            ));
        }
        // 添加瑞富宝分红交易记录
        if (dividendModels != null) {
            dividendModels.forEach(dividendModel -> wTradingRecords.add(
                WTradingRecord.builder()
                    .dividendModel(dividendModel)
                    .sortDate(dividendModel.getDividendDate() + "000000")
                    .state(1).build()
            ));
        }

        filtrateWallet(wtResult, wTradingRecords, wTradingRecordReal, beginNum, requestNum);
        wtResult.setSuccess(true);
        wtResult.setWTradingRecords(wTradingRecordReal);
        return wtResult;
    }

    /**
     * 基金详情
     *
     * @param allotNo
     */
    @Override
    public BaseResult queryFundDetail(Long userId, String allotNo) {
        User user = userDao.getEntity(userId);
        ConfirmResultModel confirmResultModel = new ConfirmResultModel();
        //交易确认  用于计算累计收益
        Map<String, Object> map = tradeConfirmQueryService.query(GlobalConstant.MAX_REQUEST_NUM, 1, 1, "1", "", user.getExternalClientId(), "", "", allotNo, "", "", "", "", "", "", "", "", "", "", "");

        // 查询结果
        List<Map<String, Object>> list = new ArrayList<>();
        HundsunUtils.ConvertToList(map, list, confirmResultModel);
        if (!confirmResultModel.getSuccess()) {
            return confirmResultModel;
        }

        // populate
        List<ConfirmModel> confirms = ModelPopulateUtils.populateConfirm(list);
        if (confirms.isEmpty()) {
            confirmResultModel.setState(0);
            return confirmResultModel;
        } else {
            ConfirmModel confirmModel = confirms.get(0);
            // 判断基金类型
            FundDetail fundDetail = fundDetailService.getFundDetail(confirmModel.getFundCode());
            String fundType = fundDetail.getFundType();
            Integer fundTypeCode = fundDetail.getFundTypeCode();
            boolean isCurrency = fundTypeCode.equals(FundConst.FUND_TYPE_CODE_CURRENCY);
            confirmResultModel.setFundType(fundType);
            // 申购  定投
            if (GlobalConstant.FUND_BUSIN_CODE_CONFIRM_BUY.equals(confirmModel.getFundBusinCode()) || GlobalConstant.FUND_BUSIN_CODE_CONFIRM_FIX_BUY.equals(confirmModel.getFundBusinCode())) {
                confirmResultModel.setTitle(GlobalConstant.BUY_TRADE_CONFIRM_TITLE);
                confirmResultModel.setExpenseTitle(GlobalConstant.BUY_TRADE_CONFIRM_EXPENSE_TITLE);
                confirmResultModel.setAffirmShareTtile(GlobalConstant.BUY_TRADE_CONFIRM_AFFIRMSHARE_TITLE);
                confirmResultModel.setExpense(confirmModel.getFareSx());
                confirmResultModel.setAffirmShare(confirmModel.getConfirmShares());
                confirmResultModel.setFundBusinCode(confirmModel.getFundBusinCode());
                confirmResultModel.setState(1);
                return confirmResultModel;
            }
            // 赎回
            if (GlobalConstant.FUND_BUSIN_CODE_CONFIRM_SELL.equals(confirmModel.getFundBusinCode()) ||
                GlobalConstant.FUND_BUSIN_CODF_CONFIRM_QUICK_SELL.equals(confirmModel.getFundBusinCode())) {
                confirmResultModel.setTitle(GlobalConstant.SELL_TRADE_CONFIRM_TITLE);
                confirmResultModel.setExpenseTitle(GlobalConstant.SELL_TRADE_CONFIRM_EXPENSE_TITLE);
                confirmResultModel.setAffirmShareTtile(GlobalConstant.SELL_TRADE_CONFIRM_AFFIRMSHARE_TITLE);

                confirmResultModel.setExpense(confirmModel.getFareSx());
                List<Lookup> tradeLookups = lookupDao.getLookupByType(RuleConstant.RULE_LOOKUP_TYPE_T0FUND);
                boolean flag = CalculateAssetsUtils.isT0Fund(tradeLookups, confirmModel.getFundCode());

                if (flag) {
                    // 如果是T0
                    confirmResultModel.setAffirmShare(confirmModel.getConfirmShares());
                } else {
                    confirmResultModel.setAffirmShare(confirmModel.getTradeConfirmBalance());
                }
                // 判断是否是货币,设置不同提示语
                if (isCurrency) {
                    confirmResultModel.setTip(GlobalConstant.SELL_TRADE_CONFIRM_TIP_T0);
                } else {
                    confirmResultModel.setTip(GlobalConstant.SELL_TRADE_CONFIRM_TIP);
                }
                confirmResultModel.setFundBusinCode(confirmModel.getFundBusinCode());
                confirmResultModel.setState(1);
                return confirmResultModel;
            }
            confirmResultModel.setState(0);
            return confirmResultModel;
        }

    }

    /**
     * 获取分类 - 交易类型
     *
     * @return
     */
    @Override
    public List<DealType> getType() {
        List<DealType> dealTypes = new ArrayList<>();
        dealTypes.add(DealType.builder().title(GlobalConstant.TYPE_BUY).value(GlobalConstant.TYPE_BUY_STATUS).build());
        dealTypes.add(DealType.builder().title(GlobalConstant.TYPE_SELL).value(GlobalConstant.TYPE_SELL_STATUS).build());
        dealTypes.add(DealType.builder().title(GlobalConstant.TYPE_FIX).value(GlobalConstant.TYPE_FIX_STATUS).build());
        dealTypes.add(DealType.builder().title(GlobalConstant.TYPE_DIVIDEND).value(GlobalConstant.TYPE_DIVIDEND_STATUS).build());
        dealTypes.add(DealType.builder().title(GlobalConstant.TYPE_TRANSFER).value(GlobalConstant.TYPE_TRANSFER_STATUS).build());
        dealTypes.add(DealType.builder().title(GlobalConstant.TYPE_OTHERS).value(GlobalConstant.TYPE_OTHERS_STATUS).build());
        return dealTypes;
    }


    /**
     * 获取组合分红记录
     *
     * @param user
     * @return
     */
    @Override
    public List<DividendModel> getPortfolioDividendApply(User user, String taSerialId) {
        log.info("queryApplys - userId=" + user.getUserId());
        DividendApplyResult result = new DividendApplyResult();
        try {
            HsDividendQryDto hsDividendQryDto;
            if (StringUtils.isNotBlank(taSerialId)) {
                hsDividendQryDto = HsDividendQryDto.builder()
                    .client_id(user.getExternalClientId())
                    .sort_direction("1")
                    .qry_beginrownum(1)
                    .reqry_recordsum_flag("1")
                    .ta_serial_id(taSerialId)
                    .request_num(GlobalConstant.MAX_REQUEST_NUM)
                    .build();
            } else {
                hsDividendQryDto = HsDividendQryDto.builder()
                    .client_id(user.getExternalClientId())
                    .sort_direction("1")
                    .qry_beginrownum(1)
                    .reqry_recordsum_flag("1")
                    .request_num(GlobalConstant.MAX_REQUEST_NUM)
                    .build();
            }
            Map<String, Object> map = dividendsQueryService.queryDto(hsDividendQryDto);
            List<Map<String, Object>> list = new ArrayList<>();
            // 查询结果
            HundsunUtils.ConvertToList(map, list, result);
            if (!result.getSuccess()) {
                return null;
            }
            // 银行名称
            List<Lookup> bankLookups = lookupDao.getLookupByType(RuleConstant.RULE_LOOKUP_TYPE_HSBANK);
            // populate

            List<DividendModel> dividendModels1 = ModelPopulateUtils.populateDividend(list, result);
            List<DividendModel> dividendModels = new ArrayList<>();


            List<String> fundCodeList = new ArrayList<String>();
            for (DividendModel dividendModel : dividendModels1) {
                if (!dividendModel.getTradeAccount().startsWith("ZH")) {
                    continue;
                }
                // 设置银行名称
                if (bankLookups != null) {
                    for (Lookup lookup : bankLookups) {
                        if (lookup.getRuleValue().equals(dividendModel.getBangNo())) {
                            dividendModel.setBankName(lookup.getRuleText());
                            break;
                        }
                    }
                }
                // 从聚源获取基金信息
                if (!fundCodeList.contains(dividendModel.getFundCode())) {
                    fundCodeList.add(dividendModel.getFundCode());
                }
                dividendModels.add(dividendModel);
            }

            List<FundNetValueResult> fundNetValueList = null;
            try {
                fundNetValueList = fundDetailService.getFundNetValueByBatch(fundCodeList, new Date());
            } catch (Exception ex) {
                ExceptionUtil.logError(log, "queryApplys - Exception:", ex);
                throw new SystemDBException("queryApplys Failure!", ex);
            }

            // 如果没有找到聚源数据，则默认为空数组
            if (fundNetValueList == null) {
                fundNetValueList = new ArrayList<>();
            }

            for (DividendModel dividendModel : dividendModels) {
                // 设置基金信息
                for (FundNetValueResult fundNetValue : fundNetValueList) {
                    if (fundNetValue == null) {
                        continue;
                    }
                    if (fundNetValue.getFundCode().equals(dividendModel.getFundCode())) {
                        dividendModel.setFundName(fundNetValue.getChiNameAbbr());
                        break;
                    }
                }

            }
            return dividendModels;
        } catch (BaseException baseException) {
            throw baseException;
        } catch (Exception exception) {
            ExceptionUtil.logError(log, "queryApplys - Exception:", exception);
            throw new SystemDBException("queryApplys Failure!", exception);
        }
    }

    /**
     * 指定基金交易记录
     *
     * @param applys
     * @param normalCode
     * @return
     */
    @Override
    public List<ApplyModel> getNormalCodeApplys(List<ApplyModel> applys, String normalCode) {
        List<ApplyModel> applyModels = new ArrayList<>();
        // 筛选对应组合交易记录
        if (StringUtils.isNotBlank(normalCode)) {
            applys.forEach(applyModel -> {
                if (normalCode.equals(applyModel.getFundCode())) {
                    applyModels.add(applyModel);
                }
            });
        }
        return applyModels;
    }

    /**
     * 获取普通基金分红记录
     *
     * @param user
     * @return
     */
    @Override
    public List<DividendModel> getNormalDividendApplys(String fundCode, User user, String taSerialId) {
        log.info("queryApplys - userId=" + user.getUserId());
        DividendApplyResult result = new DividendApplyResult();
        try {
            HsDividendQryDto hsDividendQryDto;
            if (StringUtils.isNotBlank(taSerialId)) {
                hsDividendQryDto = HsDividendQryDto.builder()
                    .client_id(user.getExternalClientId())
                    .sort_direction("1")
                    .qry_beginrownum(1)
                    .reqry_recordsum_flag("1")
                    .ta_serial_id(taSerialId)
                    .request_num(GlobalConstant.MAX_REQUEST_NUM)
                    .build();
            } else {
                hsDividendQryDto = HsDividendQryDto.builder()
                    .client_id(user.getExternalClientId())
                    .sort_direction("1")
                    .qry_beginrownum(1)
                    .reqry_recordsum_flag("1")
                    .request_num(GlobalConstant.MAX_REQUEST_NUM)
                    .build();
            }
            Map<String, Object> map = dividendsQueryService.queryDto(hsDividendQryDto);
            List<Map<String, Object>> list = new ArrayList<>();
            // 查询结果
            HundsunUtils.ConvertToList(map, list, result);
            if (!result.getSuccess()) {
                return null;
            }
            // 银行名称
            List<Lookup> bankLookups = lookupDao.getLookupByType(RuleConstant.RULE_LOOKUP_TYPE_HSBANK);

            // populate
            List<DividendModel> dividendModelList = ModelPopulateUtils.populateDividend(list, result);
            List<DividendModel> dividendModels = new ArrayList<>();
            // 把T0基金过滤掉，因为T0基金有专门的页面来显示
            dividendFilterT0(dividendModelList, true);
            //过滤组合基金记录
            dividendModelList.forEach(dividendModel -> {
                if (!dividendModel.getTradeAccount().startsWith("ZH")) {
                    dividendModels.add(dividendModel);
                }
            });

            List<String> fundCodeList = new ArrayList<String>();
            for (DividendModel dividendModel : dividendModels) {
                // 设置银行名称
                if (bankLookups != null) {
                    for (Lookup lookup : bankLookups) {
                        if (lookup.getRuleValue().equals(dividendModel.getBangNo())) {
                            dividendModel.setBankName(lookup.getRuleText());
                            break;
                        }
                    }
                }
                // 从聚源获取基金信息
                if (!fundCodeList.contains(dividendModel.getFundCode())) {
                    fundCodeList.add(dividendModel.getFundCode());
                }
            }
            List<FundNetValueResult> fundNetValueList = null;
            try {
                fundNetValueList = fundDetailService.getFundNetValueByBatch(fundCodeList, new Date());
            } catch (Exception ex) {
                ExceptionUtil.logError(log, "queryApplys - Exception:", ex);
                throw new SystemDBException("queryApplys Failure!", ex);
            }
            // 如果没有找到聚源数据，则默认为空数组
            if (fundNetValueList == null) {
                fundNetValueList = new ArrayList<>();
            }
            for (DividendModel dividendModel : dividendModels) {
                // 设置基金信息
                for (FundNetValueResult fundNetValue : fundNetValueList) {
                    if (fundNetValue == null) {
                        continue;
                    }
                    if (fundNetValue.getFundCode().equals(dividendModel.getFundCode())) {
                        dividendModel.setFundName(fundNetValue.getChiNameAbbr());
                        break;
                    }
                }
            }

            if (StringUtils.isNotBlank(fundCode)) {
                List<DividendModel> models = new ArrayList<>();
                dividendModels.forEach(dividendModel -> {
                    if (EqualsUtil.equals(dividendModel.getFundCode(), fundCode)) {
                        models.add(dividendModel);
                    }
                });
                return models;
            }
            return dividendModels;
        } catch (BaseException baseException) {
            throw baseException;
        } catch (Exception exception) {
            ExceptionUtil.logError(log, "queryApplys - Exception:", exception);
            throw new SystemDBException("queryApplys Failure!", exception);
        }
    }


    /**
     * 获取瑞富宝分红记录
     *
     * @param user
     * @return
     */
    @Override
    public List<DividendModel> getWalletDividendApplys(User user, String taSerialId) {
        log.info("queryApplys - userId=" + user.getUserId());
        DividendApplyResult result = new DividendApplyResult();
        try {

            HsDividendQryDto hsDividendQryDto;
            if (StringUtils.isNotBlank(taSerialId)) {
                hsDividendQryDto = HsDividendQryDto.builder()
                    .client_id(user.getExternalClientId())
                    .sort_direction("1")
                    .qry_beginrownum(1)
                    .reqry_recordsum_flag("1")
                    .ta_serial_id(taSerialId)
                    .request_num(GlobalConstant.MAX_REQUEST_NUM)
                    .build();
            } else {
                hsDividendQryDto = HsDividendQryDto.builder()
                    .client_id(user.getExternalClientId())
                    .sort_direction("1")
                    .qry_beginrownum(1)
                    .reqry_recordsum_flag("1")
                    .request_num(GlobalConstant.MAX_REQUEST_NUM)
                    .build();
            }
            Map<String, Object> map = dividendsQueryService.queryDto(hsDividendQryDto);
            List<Map<String, Object>> list = new ArrayList<>();
            // 查询结果
            HundsunUtils.ConvertToList(map, list, result);
            if (!result.getSuccess()) {
                return null;
            }
            // 银行名称
            List<Lookup> bankLookups = lookupDao.getLookupByType(RuleConstant.RULE_LOOKUP_TYPE_HSBANK);

            // populate
            List<DividendModel> dividendModelList = ModelPopulateUtils.populateDividend(list, result);
            List<DividendModel> dividendModels = new ArrayList<>();
            // 把T0基金过滤掉，因为T0基金有专门的页面来显示
            filterFund(dividendModelList, true);
            //过滤组合基金记录
            dividendModelList.forEach(dividendModel -> {
                if (!dividendModel.getTradeAccount().startsWith("ZH")) {
                    dividendModels.add(dividendModel);
                }
            });

            List<String> fundCodeList = new ArrayList<String>();
            for (DividendModel dividendModel : dividendModels) {
                // 设置银行名称
                if (bankLookups != null) {
                    for (Lookup lookup : bankLookups) {
                        if (lookup.getRuleValue().equals(dividendModel.getBangNo())) {
                            dividendModel.setBankName(lookup.getRuleText());
                            break;
                        }
                    }
                }
                // 从聚源获取基金信息
                if (!fundCodeList.contains(dividendModel.getFundCode())) {
                    fundCodeList.add(dividendModel.getFundCode());
                }
            }
            List<FundNetValueResult> fundNetValueList = null;
            try {
                fundNetValueList = fundDetailService.getFundNetValueByBatch(fundCodeList, new Date());
            } catch (Exception ex) {
                ExceptionUtil.logError(log, "queryApplys - Exception:", ex);
                throw new SystemDBException("queryApplys Failure!", ex);
            }
            // 如果没有找到聚源数据，则默认为空数组
            if (fundNetValueList == null) {
                fundNetValueList = new ArrayList<>();
            }
            for (DividendModel dividendModel : dividendModels) {
                // 设置基金信息
                for (FundNetValueResult fundNetValue : fundNetValueList) {
                    if (fundNetValue == null) {
                        continue;
                    }
                    if (fundNetValue.getFundCode().equals(dividendModel.getFundCode())) {
                        dividendModel.setFundName(fundNetValue.getChiNameAbbr());
                        break;
                    }
                }
            }
            return dividendModels;
        } catch (BaseException baseException) {
            throw baseException;
        } catch (Exception exception) {
            ExceptionUtil.logError(log, "queryApplys - Exception:", exception);
            throw new SystemDBException("queryApplys Failure!", exception);
        }
    }


    /**
     * 过滤非T0基金
     *
     * @param dividendModels
     * @param filterT0
     */
    @Override
    public void filterFund(List<DividendModel> dividendModels, boolean filterT0) {
        if (filterT0) {
            List<Lookup> T0Funds = lookupDao.getLookupByType(RuleConstant.RULE_LOOKUP_TYPE_T0FUND);
            Iterator<DividendModel> iterator = dividendModels.iterator();
            while (iterator.hasNext()) {
                DividendModel model = iterator.next();
                if (!ModelPopulateUtils.isT0Fund(T0Funds, model.getFundCode())) {
                    iterator.remove();
                }
            }
        }
    }


    /**
     * 普通基金过滤T0
     *
     * @param applys
     * @param filterT0
     */
    @Override
    public void normalFilterT0(List<ApplyModel> applys, boolean filterT0) {
        if (filterT0) {
            List<Lookup> T0Funds = lookupDao.getLookupByType(RuleConstant.RULE_LOOKUP_TYPE_T0FUND);
            Iterator<ApplyModel> iterator = applys.iterator();
            while (iterator.hasNext()) {
                ApplyModel model = iterator.next();
                if (ModelPopulateUtils.isT0Fund(T0Funds, model.getFundCode())) {
                    iterator.remove();
                }
            }
        }
    }



    /**
     * 分红过滤T0基金
     *
     * @param dividendModels
     * @param filterT0
     */
    @Override
    public void dividendFilterT0(List<DividendModel> dividendModels, boolean filterT0) {
        if (filterT0) {
            List<Lookup> T0Funds = lookupDao.getLookupByType(RuleConstant.RULE_LOOKUP_TYPE_T0FUND);
            Iterator<DividendModel> iterator = dividendModels.iterator();
            while (iterator.hasNext()) {
                DividendModel model = iterator.next();
                if (ModelPopulateUtils.isT0Fund(T0Funds, model.getFundCode())) {
                    iterator.remove();
                }
            }
        }
    }



    /**
     * 筛选组合进行中的交易
     *
     * @param portfolioApplyModels 全部交易记录
     * @return
     */
    @Override
    public List<PortfolioApplyModel> getIntradingApplys(List<PortfolioApplyModel> portfolioApplyModels) {
        List<PortfolioApplyModel> portfolioApplyModelList = new ArrayList<>();
        portfolioApplyModels.forEach(portfolioApplyModel -> {
            if (GlobalConstant.TACONFIRM_FLAG_UNCONFIRM.equals(portfolioApplyModel.getTAConfirmFlag())) {
                portfolioApplyModelList.add(portfolioApplyModel);
            }
        });
        return portfolioApplyModelList;
    }

    /**
     * 基金正在交易的记录
     *
     * @param applys
     * @return
     */
    @Override
    public List<ApplyModel> getNormalIntradingApplys(List<ApplyModel> applys) {
        List<ApplyModel> applyModelList = new ArrayList<>();
        applys.forEach(applyModel -> {
            if (GlobalConstant.TACONFIRM_FLAG_UNCONFIRM.equals(applyModel.getTAConfirmFlag())) {
                applyModelList.add(applyModel);
            }
        });
        return applyModelList;
    }


    /**
     * 指定组合交易记录
     *
     * @param portfolioApplys 全部交易记录
     * @param tradeAccount   组合交易代码
     * @return
     */
    @Override
    public List<PortfolioApplyModel> getPortfolioCodeApplys(List<PortfolioApplyModel> portfolioApplys, String tradeAccount) {
        List<PortfolioApplyModel> portfolioApplyModels = new ArrayList<>();
        // 筛选对应组合交易记录
        if (StringUtils.isNotBlank(tradeAccount)) {
            portfolioApplys.forEach(portfolioApplyModel -> {
                if (tradeAccount.equals(portfolioApplyModel.getTradeAcco())) {
                    portfolioApplyModels.add(portfolioApplyModel);
                }
            });
        }
        return portfolioApplyModels;
    }

    /**
     * 筛选组合业务数据
     *
     * @param portfolioApplyModels 交易记录
     * @param busniess             业务状态
     */
    @Override
    public List<PortfolioApplyModel> busniessData(List<PortfolioApplyModel> portfolioApplyModels, String busniess) {
        List<PortfolioApplyModel> portfolioApplyModelList = new ArrayList<>();

        // 如果是定投,需要匹配所有定投状态
        if (GlobalConstant.FUND_BUSIN_CODE_APPLY_FIX.equals(busniess)) {
            GlobalConstant.FIX_BUY_APPLY_CODES.forEach(fix -> portfolioApplyModels.forEach(portfolioApplyModel -> {
                if (fix.equals(portfolioApplyModel.getFundBusinCode())) {
                    portfolioApplyModelList.add(portfolioApplyModel);
                }
            }));
            return portfolioApplyModelList;
        }

        // 如果是其他
        if (GlobalConstant.TYPE_OTHERS.equals(busniess)) {
            portfolioApplyModels.forEach(portfolioApplyModel -> {
                boolean flag = false;
                for (String f : GlobalConstant.FIX_BUY_APPLY_CODES) {
                    flag = f.equals(portfolioApplyModel.getFundBusinCode());
                    if (flag) {
                        break;
                    }
                }
                if (!GlobalConstant.FUND_BUSIN_CODE_APPLY_BUY.equals(portfolioApplyModel.getFundBusinCode()) &&
                    !flag &&
                    GlobalConstant.FUND_BUSIN_CODE_APPLY_SELL.equals(portfolioApplyModel.getFundBusinCode()) &&
                    GlobalConstant.PORTFOLIO_TRANSFER.equals(portfolioApplyModel.getFundBusinCode())) {
                    portfolioApplyModelList.add(portfolioApplyModel);
                }
            });
            return portfolioApplyModelList;
        }

        // 如果是赎回,需要过滤 普通赎回和快速赎回
        if (busniess.equals(GlobalConstant.FUND_BUSIN_CODE_APPLY_SELL)) {
            portfolioApplyModels.forEach(portfolioApplyModel -> {
                if (!GlobalConstant.PORTFOLIO_TRANSFER.equals(portfolioApplyModel.getFundBusinNameReal())) {
                    if (busniess.equals(portfolioApplyModel.getFundBusinCode()) || GlobalConstant.FUND_BUSIN_CODE_T0_FAST_APPLY_SELL.equals(portfolioApplyModel.getFundBusinCode())) {
                        portfolioApplyModelList.add(portfolioApplyModel);
                    }
                }
            });
            return portfolioApplyModelList;
        }

        // 如果是组合调仓
        if (GlobalConstant.PORTFOLIO_TRANSFER.equals(busniess)) {
            portfolioApplyModels.forEach(portfolioApplyModel -> {
                if (GlobalConstant.PORTFOLIO_TRANSFER.equals(portfolioApplyModel.getFundBusinNameReal())) {
                    portfolioApplyModelList.add(portfolioApplyModel);
                }
            });
            return portfolioApplyModelList;
        }

        portfolioApplyModels.forEach(portfolioApplyModel -> {
            if (busniess.equals(portfolioApplyModel.getFundBusinCode())) {
                portfolioApplyModelList.add(portfolioApplyModel);
            }
        });
        return portfolioApplyModelList;
    }

    /**
     * 基金指定业务交易数据
     *
     * @param applys
     * @param busniess
     * @return
     */
    @Override
    public List<ApplyModel> normalBusniessData(List<ApplyModel> applys, String busniess) {
        List<ApplyModel> applyModels = new ArrayList<>();

        // 如果是定投,需要匹配所有定投状态
        if (GlobalConstant.FUND_BUSIN_CODE_APPLY_FIX.equals(busniess)) {
            GlobalConstant.FIX_BUY_APPLY_CODES.forEach(fix -> applys.forEach(applyModel -> {
                if (fix.equals(applyModel.getFundBusinCode())) {
                    applyModels.add(applyModel);
                }
            }));
            return applyModels;
        }

        // 如果是其他
        if (GlobalConstant.TYPE_OTHERS.equals(busniess)) {
            applys.forEach(applyModel -> {
                boolean flag = false;
                for (String f : GlobalConstant.FIX_BUY_APPLY_CODES) {
                    flag = f.equals(applyModel.getFundBusinCode());
                    if (flag) {
                        break;
                    }
                }
                if (!GlobalConstant.FUND_BUSIN_CODE_APPLY_BUY.equals(applyModel.getFundBusinCode()) && !flag &&
                    GlobalConstant.FUND_BUSIN_CODE_APPLY_SELL.equals(applyModel.getFundBusinCode()) &&
                    GlobalConstant.PORTFOLIO_TRANSFER.equals(applyModel.getFundBusinCode())) {
                    applyModels.add(applyModel);
                }
            });
            return applyModels;
        }
        // 如果是赎回,需要过滤 普通赎回和快速赎回
        if (busniess.equals(GlobalConstant.FUND_BUSIN_CODE_APPLY_SELL)) {
            applys.forEach(applyModel -> {
                if (busniess.equals(applyModel.getFundBusinCode()) || GlobalConstant.FUND_BUSIN_CODE_T0_FAST_APPLY_SELL.equals(applyModel.getFundBusinCode())) {
                    applyModels.add(applyModel);
                }
            });
            return applyModels;
        }
        applys.forEach(applyModel -> {
            if (busniess.equals(applyModel.getFundBusinCode())) {
                applyModels.add(applyModel);
            }
        });
        return applyModels;
    }


    /**
     * 组合记录排序
     */
    @Override
    public void filtrate(BaseListResult result, List<PTradingRecord> pTradingRecords, List<PTradingRecord> pTradingRecordReal, Integer beginNum, Integer requestNum) {
        // 按日期倒叙排序
        Collections.sort(pTradingRecords, new Comparator<PTradingRecord>() {
            @Override
            public int compare(PTradingRecord o1, PTradingRecord o2) {
                String o1No = o1.getSortDate(), o2No = o2.getSortDate();
                return 0 - o1No.compareTo(o2No);
            }
        });
        result.setTotalCount(Long.valueOf(pTradingRecords.size()));
        result.setRowCount(Long.valueOf(pTradingRecords.size()));
        for (int i = 1; i <= pTradingRecords.size(); i++) {
            if (i >= beginNum && i < requestNum + beginNum) {
                pTradingRecordReal.add(pTradingRecords.get(i - 1));
            }
        }
    }

    /**
     * 基金记录排序
     */
    @Override
    public void filtrateFunds(BaseListResult result, List<NTradingRecord> nTradingRecords, List<NTradingRecord> nTradingRecordReal, Integer beginNum, Integer requestNum) {
        // 按日期倒叙排序
        Collections.sort(nTradingRecords, new Comparator<NTradingRecord>() {
            @Override
            public int compare(NTradingRecord o1, NTradingRecord o2) {
                String o1No = o1.getSortDate(), o2No = o2.getSortDate();
                return 0 - o1No.compareTo(o2No);
            }
        });
        result.setTotalCount(Long.valueOf(nTradingRecords.size()));
        result.setRowCount(Long.valueOf(nTradingRecords.size()));
        for (int i = 1; i <= nTradingRecords.size(); i++) {
            if (i >= beginNum && i < requestNum + beginNum) {
                nTradingRecordReal.add(nTradingRecords.get(i - 1));
            }
        }
    }

    /**
     * 瑞富宝记录排序
     */
    @Override
    public void filtrateWallet(BaseListResult result, List<WTradingRecord> wTradingRecords, List<WTradingRecord> wTradingRecordReal, Integer beginNum, Integer requestNum) {
        // 按日期倒叙排序
        Collections.sort(wTradingRecords, new Comparator<WTradingRecord>() {
            @Override
            public int compare(WTradingRecord o1, WTradingRecord o2) {
                String o1No = o1.getSortDate(), o2No = o2.getSortDate();
                return 0 - o1No.compareTo(o2No);
            }
        });
        result.setTotalCount(Long.valueOf(wTradingRecords.size()));
        result.setRowCount(Long.valueOf(wTradingRecords.size()));
        for (int i = 1; i <= wTradingRecords.size(); i++) {
            if (i >= beginNum && i < requestNum + beginNum) {
                wTradingRecordReal.add(wTradingRecords.get(i - 1));
            }
        }
    }

    @Override
    public String businessCode(String business) {
        if (StringUtils.isNotBlank(business)) {
            switch (business) {
                case "1":
                    // 申购
                    business = GlobalConstant.FUND_BUSIN_CODE_APPLY_BUY;
                    break;
                case "2":
                    // 赎回
                    business = GlobalConstant.FUND_BUSIN_CODE_APPLY_SELL;
                    break;
                case "3":
                    // 定投
                    business = GlobalConstant.FUND_BUSIN_CODE_APPLY_FIX;
                    break;
                case "4":
                    // 分红
                    business = GlobalConstant.FUND_BUSIN_CODE_APPLY_BOUNS;
                    break;
                case "5":
                    // 组合调仓
                    business = GlobalConstant.PORTFOLIO_TRANSFER;
                    break;
                case "6":
                    // 其他
                    break;
                default:
                    business = "";
                    break;
            }
            return business;
        }
        return business;
    }

    //设置组合 交易记录内层记录信息   因为两个地方重复使用 所以提取出来
    private void setApply(List<ConfirmModel> confirms, ApplyModel apply, List<FundNetValueResult> fundNetValueList, PortfolioApplyModel portfolioApplyModel) {
        for (ConfirmModel confirmModel : confirms) {
            if (apply.getAllotNo().equals(confirmModel.getAllotNo())) {
                apply.setShares(confirmModel.getConfirmShares());
                apply.setBalance(confirmModel.getConfirmBalance());

                switch (confirmModel.getFundBusinCode()) {
                    //申购
                    case GlobalConstant.FUND_BUSIN_CODE_CONFIRM_BUY:
                        apply.setExpense(confirmModel.getFareSx());
                        apply.setExpenseTtile(GlobalConstant.BUY_TRADE_CONFIRM_EXPENSE_TITLE);
                        break;
                    //赎回
                    case GlobalConstant.FUND_BUSIN_CODE_CONFIRM_SELL:
                        apply.setExpense(confirmModel.getFareSx());
                        apply.setExpenseTtile(GlobalConstant.SELL_TRADE_CONFIRM_EXPENSE_TITLE);
                        break;
                    default:
                        break;
                }
                break;
            }
        }
        // 设置基金信息
        for (FundNetValueResult fundNetValue : fundNetValueList) {
            if (fundNetValue == null) {
                continue;
            }
            if (fundNetValue.getFundCode().equals(apply.getFundCode())) {
                apply.setFundName(fundNetValue.getChiNameAbbr());
                break;
            }
        }
        apply.setStatusString(ModelPopulateUtils.getStatusString(apply));
        portfolioApplyModel.getFundApplys().add(apply);
    }
}
